if (!dojo._hasResource["dojo._base.event"]) { //_hasResource checks added by build. Do not use _hasResource directly in your code.
    dojo._hasResource["dojo._base.event"] = true;
    dojo.provide("dojo._base.event");
    dojo.require("dojo._base.connect");

    // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA

    (function() {
        // DOM event listener machinery
        var del = (dojo._event_listener = {
            add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp) {
                if (!node) {
                    return;
                }
                name = del._normalizeEventName(name);
                fp = del._fixCallback(name, fp);
                var oname = name;
                if (!dojo.isIE && (name == "mouseenter" || name == "mouseleave")) {
                    var ofp = fp;
                    //oname = name;
                    name = (name == "mouseenter") ? "mouseover" : "mouseout";
                    fp = function(e) {
                        // thanks ben!
                        if (!dojo.isDescendant(e.relatedTarget, node)) {
                            // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
                            return ofp.call(this, e);
                        }
                    }
                }
                node.addEventListener(name, fp, false);
                return fp;
                /*Handle*/
            },
            remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle) {
                // summary:
                //		clobbers the listener from the node
                // node:
                //		DOM node to attach the event to
                // event:
                //		the name of the handler to remove the function from
                // handle:
                //		the handle returned from add
                if (node) {
                    node.removeEventListener(del._normalizeEventName(event), handle, false);
                }
            },
            _normalizeEventName: function(/*String*/name) {
                // Generally, name should be lower case, unless it is special
                // somehow (e.g. a Mozilla DOM event).
                // Remove 'on'.
                return name.slice(0, 2) == "on" ? name.slice(2) : name;
            },
            _fixCallback: function(/*String*/name, fp) {
                // By default, we only invoke _fixEvent for 'keypress'
                // If code is added to _fixEvent for other events, we have
                // to revisit this optimization.
                // This also applies to _fixEvent overrides for Safari and Opera
                // below.
                return name != "keypress" ? fp : function(e) {
                    return fp.call(this, del._fixEvent(e, this));
                };
            },
            _fixEvent: function(evt, sender) {
                // _fixCallback only attaches us to keypress.
                // Switch on evt.type anyway because we might
                // be called directly from dojo.fixEvent.
                switch (evt.type) {
                    case "keypress":
                        del._setKeyChar(evt);
                        break;
                }
                return evt;
            },
            _setKeyChar: function(evt) {
                evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
            }
        });

        // DOM events

        dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender) {
            // summary:
            //		normalizes properties on the event object including event
            //		bubbling methods, keystroke normalization, and x/y positions
            // evt: Event
            //		native event object
            // sender: DOMNode
            //		node to treat as "currentTarget"
            return del._fixEvent(evt, sender);
        }

        dojo.stopEvent = function(/*Event*/evt) {
            // summary:
            //		prevents propagation and clobbers the default action of the
            //		passed event
            // evt: Event
            //		The event object. If omitted, window.event is used on IE.
            evt.preventDefault();
            evt.stopPropagation();
            // NOTE: below, this method is overridden for IE
        }

        // the default listener to use on dontFix nodes, overriden for IE
        var node_listener = dojo._listener;

        // Unify connect and event listeners
        dojo._connect = function(obj, event, context, method, dontFix) {
            // FIXME: need a more strict test
            var isNode = obj && (obj.nodeType || obj.attachEvent || obj.addEventListener);
            // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
            // we need the third option to provide leak prevention on broken browsers (IE)
            var lid = !isNode ? 0 :
                      (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
            // create a listener
            var h = l.add(obj, event, dojo.hitch(context, method));
            // formerly, the disconnect package contained "l" directly, but if client code
            // leaks the disconnect package (by connecting it to a node), referencing "l"
            // compounds the problem.
            // instead we return a listener id, which requires custom _disconnect below.
            // return disconnect package
            return [ obj, event, h, lid ];
        }

        dojo._disconnect = function(obj, event, handle, listener) {
            ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
        }

        // Constants

        // Public: client code should test
        // keyCode against these named constants, as the
        // actual codes can vary by browser.
        dojo.keys = {
            // summary: definitions for common key values
            BACKSPACE: 8,
            TAB: 9,
            CLEAR: 12,
            ENTER: 13,
            SHIFT: 16,
            CTRL: 17,
            ALT: 18,
            PAUSE: 19,
            CAPS_LOCK: 20,
            ESCAPE: 27,
            SPACE: 32,
            PAGE_UP: 33,
            PAGE_DOWN: 34,
            END: 35,
            HOME: 36,
            LEFT_ARROW: 37,
            UP_ARROW: 38,
            RIGHT_ARROW: 39,
            DOWN_ARROW: 40,
            INSERT: 45,
            DELETE: 46,
            HELP: 47,
            LEFT_WINDOW: 91,
            RIGHT_WINDOW: 92,
            SELECT: 93,
            NUMPAD_0: 96,
            NUMPAD_1: 97,
            NUMPAD_2: 98,
            NUMPAD_3: 99,
            NUMPAD_4: 100,
            NUMPAD_5: 101,
            NUMPAD_6: 102,
            NUMPAD_7: 103,
            NUMPAD_8: 104,
            NUMPAD_9: 105,
            NUMPAD_MULTIPLY: 106,
            NUMPAD_PLUS: 107,
            NUMPAD_ENTER: 108,
            NUMPAD_MINUS: 109,
            NUMPAD_PERIOD: 110,
            NUMPAD_DIVIDE: 111,
            F1: 112,
            F2: 113,
            F3: 114,
            F4: 115,
            F5: 116,
            F6: 117,
            F7: 118,
            F8: 119,
            F9: 120,
            F10: 121,
            F11: 122,
            F12: 123,
            F13: 124,
            F14: 125,
            F15: 126,
            NUM_LOCK: 144,
            SCROLL_LOCK: 145
        };

        // IE event normalization
        if (dojo.isIE) {
            var _trySetKeyCode = function(e, code) {
                try {
                    // squelch errors when keyCode is read-only
                    // (e.g. if keyCode is ctrl or shift)
                    return (e.keyCode = code);
                } catch(e) {
                    return 0;
                }
            }

            // by default, use the standard listener
            var iel = dojo._listener;
            // dispatcher tracking property
            if (!dojo.config._allow_leaks) {
                // custom listener that handles leak protection for DOM events
                node_listener = iel = dojo._ie_listener = {
                    // support handler indirection: event handler functions are
                    // referenced here. Event dispatchers hold only indices.
                    handlers: [],
                    // add a listener to an object
                    add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener) {
                        source = source || dojo.global;
                        var f = source[method];
                        if (!f || !f._listeners) {
                            var d = dojo._getIeDispatcher();
                            // original target function is special
                            d.target = f && (ieh.push(f) - 1);
                            // dispatcher holds a list of indices into handlers table
                            d._listeners = [];
                            // redirect source to dispatcher
                            f = source[method] = d;
                        }
                        return f._listeners.push(ieh.push(listener) - 1);
                        /*Handle*/
                    },
                    // remove a listener from an object
                    remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle) {
                        var f = (source || dojo.global)[method], l = f && f._listeners;
                        if (f && l && handle--) {
                            delete ieh[l[handle]];
                            delete l[handle];
                        }
                    }
                };
                // alias used above
                var ieh = iel.handlers;
            }

            dojo.mixin(del, {
                add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp) {
                    if (!node) {
                        return;
                    } // undefined
                    event = del._normalizeEventName(event);
                    if (event == "onkeypress") {
                        // we need to listen to onkeydown to synthesize
                        // keypress events that otherwise won't fire
                        // on IE
                        var kd = node.onkeydown;
                        if (!kd || !kd._listeners || !kd._stealthKeydownHandle) {
                            var h = del.add(node, "onkeydown", del._stealthKeyDown);
                            kd = node.onkeydown;
                            kd._stealthKeydownHandle = h;
                            kd._stealthKeydownRefs = 1;
                        } else {
                            kd._stealthKeydownRefs++;
                        }
                    }
                    return iel.add(node, event, del._fixCallback(fp));
                },
                remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle) {
                    event = del._normalizeEventName(event);
                    iel.remove(node, event, handle);
                    if (event == "onkeypress") {
                        var kd = node.onkeydown;
                        if (--kd._stealthKeydownRefs <= 0) {
                            iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
                            delete kd._stealthKeydownHandle;
                        }
                    }
                },
                _normalizeEventName: function(/*String*/eventName) {
                    // Generally, eventName should be lower case, unless it is
                    // special somehow (e.g. a Mozilla event)
                    // ensure 'on'
                    return eventName.slice(0, 2) != "on" ? "on" + eventName : eventName;
                },
                _nop: function() {
                },
                _fixEvent: function(/*Event*/evt, /*DOMNode*/sender) {
                    // summary:
                    //		normalizes properties on the event object including event
                    //		bubbling methods, keystroke normalization, and x/y positions
                    // evt: native event object
                    // sender: node to treat as "currentTarget"
                    if (!evt) {
                        var w = sender &&
                                (sender.ownerDocument || sender.document || sender).parentWindow ||
                                window;
                        evt = w.event;
                    }
                    if (!evt) {
                        return(evt);
                    }
                    evt.target = evt.srcElement;
                    evt.currentTarget = (sender || evt.srcElement);
                    evt.layerX = evt.offsetX;
                    evt.layerY = evt.offsetY;
                    // FIXME: scroll position query is duped from dojo.html to
                    // avoid dependency on that entire module. Now that HTML is in
                    // Base, we should convert back to something similar there.
                    var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
                    // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
                    // here rather than document.body
                    var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ?
                                  doc.body : doc.documentElement;
                    var offset = dojo._getIeDocumentElementOffset();
                    evt.pageX =
                    evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
                    evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
                    if (evt.type == "mouseover") {
                        evt.relatedTarget = evt.fromElement;
                    }
                    if (evt.type == "mouseout") {
                        evt.relatedTarget = evt.toElement;
                    }
                    evt.stopPropagation = del._stopPropagation;
                    evt.preventDefault = del._preventDefault;
                    return del._fixKeys(evt);
                },
                _fixKeys: function(evt) {
                    switch (evt.type) {
                        case "keypress":
                            var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
                            if (c == 10) {
                                // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
                                c = 0;
                                evt.keyCode = 13;
                            } else if (c == 13 || c == 27) {
                                c = 0; // Mozilla considers ENTER and ESC non-printable
                            } else if (c == 3) {
                                c = 99; // Mozilla maps CTRL-BREAK to CTRL-c
                            }
                        // Mozilla sets keyCode to 0 when there is a charCode
                        // but that stops the event on IE.
                            evt.charCode = c;
                            del._setKeyChar(evt);
                            break;
                    }
                    return evt;
                },
                // some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
                // we map those virtual key codes to ascii here
                // not valid for all (non-US) keyboards, so maybe we shouldn't bother
                _punctMap: {
                    106:42,
                    111:47,
                    186:59,
                    187:43,
                    188:44,
                    189:45,
                    190:46,
                    191:47,
                    192:96,
                    219:91,
                    220:92,
                    221:93,
                    222:39
                },
                _stealthKeyDown: function(evt) {
                    // IE doesn't fire keypress for most non-printable characters.
                    // other browsers do, we simulate it here.
                    var kp = evt.currentTarget.onkeypress;
                    // only works if kp exists and is a dispatcher
                    if (!kp || !kp._listeners) {
                        return;
                    }
                    // munge key/charCode
                    var k = evt.keyCode;
                    // These are Windows Virtual Key Codes
                    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
                    var unprintable = (k != 13) && (k != 32) && (k != 27) && (k < 48 || k > 90) &&
                                      (k < 96 || k > 111) && (k < 186 || k > 192) &&
                                      (k < 219 || k > 222);
                    // synthesize keypress for most unprintables and CTRL-keys
                    if (unprintable || evt.ctrlKey) {
                        var c = unprintable ? 0 : k;
                        if (evt.ctrlKey) {
                            if (k == 3 || k == 13) {
                                return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
                            } else if (c > 95 && c < 106) {
                                c -= 48; // map CTRL-[numpad 0-9] to ASCII
                            } else if ((!evt.shiftKey) && (c >= 65 && c <= 90)) {
                                c += 32; // map CTRL-[A-Z] to lowercase
                            } else {
                                c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
                            }
                        }
                        // simulate a keypress event
                        var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
                        kp.call(evt.currentTarget, faux);
                        evt.cancelBubble = faux.cancelBubble;
                        evt.returnValue = faux.returnValue;
                        _trySetKeyCode(evt, faux.keyCode);
                    }
                },
                // Called in Event scope
                _stopPropagation: function() {
                    this.cancelBubble = true;
                },
                _preventDefault: function() {
                    // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
                    // ctrl-combinations that correspond to menu accelerator keys).
                    // Otoh, it prevents upstream listeners from getting this information
                    // Try to split the difference here by clobbering keyCode only for ctrl
                    // combinations. If you still need to access the key upstream, bubbledKeyCode is
                    // provided as a workaround.
                    this.bubbledKeyCode = this.keyCode;
                    if (this.ctrlKey) {
                        _trySetKeyCode(this, 0);
                    }
                    this.returnValue = false;
                }
            });

            // override stopEvent for IE
            dojo.stopEvent = function(evt) {
                evt = evt || window.event;
                del._stopPropagation.call(evt);
                del._preventDefault.call(evt);
            }
        }

        del._synthesizeEvent = function(evt, props) {
            var faux = dojo.mixin({}, evt, props);
            del._setKeyChar(faux);
            // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
            // but it throws an error when preventDefault is invoked on Safari
            // does Event.preventDefault not support "apply" on Safari?
            faux.preventDefault = function() {
                evt.preventDefault();
            };
            faux.stopPropagation = function() {
                evt.stopPropagation();
            };
            return faux;
        }

        // Opera event normalization
        if (dojo.isOpera) {
            dojo.mixin(del, {
                _fixEvent: function(evt, sender) {
                    switch (evt.type) {
                        case "keypress":
                            var c = evt.which;
                            if (c == 3) {
                                c = 99; // Mozilla maps CTRL-BREAK to CTRL-c
                            }
                        // can't trap some keys at all, like INSERT and DELETE
                        // there is no differentiating info between DELETE and ".", or INSERT and "-"
                            c = ((c < 41) && (!evt.shiftKey) ? 0 : c);
                            if ((evt.ctrlKey) && (!evt.shiftKey) && (c >= 65) && (c <= 90)) {
                                // lowercase CTRL-[A-Z] keys
                                c += 32;
                            }
                            return del._synthesizeEvent(evt, { charCode: c });
                    }
                    return evt;
                }
            });
        }

        // Safari event normalization
        if (dojo.isSafari) {
            dojo.mixin(del, {
                _fixEvent: function(evt, sender) {
                    switch (evt.type) {
                        case "keypress":
                            var c = evt.charCode, s = evt.shiftKey, k = evt.keyCode;
                        // FIXME: This is a hack, suggest we rethink keyboard strategy.
                        // Arrow and page keys have 0 "keyCode" in keypress events.on Safari for Windows
                            k = k || identifierMap[evt.keyIdentifier] || 0;
                            if (evt.keyIdentifier == "Enter") {
                                c = 0; // differentiate Enter from CTRL-m (both code 13)
                            } else if ((evt.ctrlKey) && (c > 0) && (c < 27)) {
                                c += 96; // map CTRL-[A-Z] codes to ASCII
                            } else if (c == dojo.keys.SHIFT_TAB) {
                                c = dojo.keys.TAB; // morph SHIFT_TAB into TAB + shiftKey: true
                                s = true;
                            } else {
                                c = (c >= 32 && c < 63232 ? c : 0); // avoid generating keyChar for non-printables
                            }
                            return del._synthesizeEvent(evt, {charCode: c, shiftKey: s, keyCode: k});
                    }
                    return evt;
                }
            });

            dojo.mixin(dojo.keys, {
                SHIFT_TAB: 25,
                UP_ARROW: 63232,
                DOWN_ARROW: 63233,
                LEFT_ARROW: 63234,
                RIGHT_ARROW: 63235,
                F1: 63236,
                F2: 63237,
                F3: 63238,
                F4: 63239,
                F5: 63240,
                F6: 63241,
                F7: 63242,
                F8: 63243,
                F9: 63244,
                F10: 63245,
                F11: 63246,
                F12: 63247,
                PAUSE: 63250,
                DELETE: 63272,
                HOME: 63273,
                END: 63275,
                PAGE_UP: 63276,
                PAGE_DOWN: 63277,
                INSERT: 63302,
                PRINT_SCREEN: 63248,
                SCROLL_LOCK: 63249,
                NUM_LOCK: 63289
            });
            var dk = dojo.keys, identifierMap = { "Up": dk.UP_ARROW, "Down": dk.DOWN_ARROW, "Left": dk.LEFT_ARROW, "Right": dk.RIGHT_ARROW, "PageUp": dk.PAGE_UP, "PageDown": dk.PAGE_DOWN };
        }
    })();

    if (dojo.isIE) {
        // keep this out of the closure
        // closing over 'iel' or 'ieh' b0rks leak prevention
        // ls[i] is an index into the master handler array
        dojo._ieDispatcher = function(args, sender) {
            var ap = Array.prototype, h = dojo._ie_listener.handlers, c = args.callee, ls = c._listeners, t = h[c.target];
            // return value comes from original target function
            var r = t && t.apply(sender, args);
            // invoke listeners after target function
            for (var i in ls) {
                if (!(i in ap)) {
                    h[ls[i]].apply(sender, args);
                }
            }
            return r;
        }
        dojo._getIeDispatcher = function() {
            // ensure the returned function closes over nothing
            return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
        }
        // keep this out of the closure to reduce RAM allocation
        dojo._event_listener._fixCallback = function(fp) {
            var f = dojo._event_listener._fixEvent;
            return function(e) {
                return fp.call(this, f(e, this));
            };
        }
    }

}
